﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace OSGeo.MapGuide
{
    /// <summary>
    /// A base class for a strongly-typed feature data access interface to a feature source. Subclasses are
    /// responsible for converting class types to/from property collections.
    /// </summary>
    /// <typeparam name="T">The class type that represents features in this feature source</typeparam>
    public abstract class MgTypedFeatureRepository<T> : MgFeatureRepository where T : class
    {
        protected MgTypedFeatureRepository(string featureSourceId, MgFeatureService service)
            : base(featureSourceId, service)
        { }

        protected MgTypedFeatureRepository(MgResourceIdentifier featureSourceId, MgFeatureService service)
            : base(featureSourceId, service)
        { }

        /// <summary>
        /// Generates an identity filter from the given object
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        protected abstract string GenerateFilter(T obj);

        /// <summary>
        /// Creates a property collection from the given object
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        protected abstract MgPropertyCollection GenerateProperties(T obj);

        /// <summary>
        /// Creates an object from the given property collection
        /// </summary>
        /// <param name="props"></param>
        /// <returns></returns>
        protected abstract T CreateObject(MgPropertyCollection props);

        /// <summary>
        /// Inserts a new object into this feature source
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="useTransaction"></param>
        /// <returns></returns>
        public virtual MgInsertResult Insert(T obj, bool useTransaction)
        {
            try
            {
                MgPropertyCollection propVals = GenerateProperties(obj);
                MgInsertResult res = base.InsertFeature(propVals, useTransaction);
                return res;
            }
            catch
            {
                throw;
            }
            finally
            {
                _commandQueue.Clear();
            }
        }

        /// <summary>
        /// Updates an object or group of objects in this feature source
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="useTransaction"></param>
        /// <returns></returns>
        public virtual int Update(T obj, bool useTransaction)
        {
            try
            {
                MgPropertyCollection propVals = GenerateProperties(obj);
                string filter = GenerateFilter(obj);

                int updated = base.UpdateFeatures(propVals, filter, useTransaction);
                return updated;
            }
            catch
            {
                throw;
            }
            finally
            {
                _commandQueue.Clear();
            }
        }

        /// <summary>
        /// Selects features from this feature source
        /// </summary>
        /// <param name="filter"></param>
        /// <returns></returns>
        public virtual IEnumerable<T> Select(string filter)
        {
            IEnumerable<MgPropertyCollection> features = SelectFeatures(filter, null, null);
            foreach (MgPropertyCollection feature in features)
            {
                yield return CreateObject(feature);
            }
        }
    }
}
